﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace KZ400B
{
    public static class DSPResCodeCollection
    {
        const string m_VS1 = ""; 
    }

    public class ProtocolV2
    {
        public enum ResponseResult
        { 
            Success = 2,
            Failed  = 3,
            WrongFormat = 0x57,
        }

        public class ResponseManager
        {
            static Dictionary<string, string> m_RM = new Dictionary<string, string>();
            const string knFormat = "@{0}_{1}_({2})";
            public static string getKeyName(FunctionCode fc, bool right)
            {
                return getKeyName(fc,string.Empty,right);
            }

            public static string getKeyName(FunctionCode fc, string axName, bool right)
            {
                return string.Format(knFormat
                    ,fc.FCode == CommFunctionCode.Query ? CommFlag.Query : fc.ToString()
                    ,string.IsNullOrEmpty( axName ) ? Axle.AllAxleName : axName 
                    ,Respond.getRepRst(right)
                    );
            }

            public static string getResonseCode(FunctionCode fc, string axName)
            {
                return getResonseCode(fc, axName, false, null);
            }

            public static string getResonseCode(FunctionCode fc, string axName, bool right)
            {
                return getResonseCode(fc, axName, right, null);
            }


            public static string getResonseCode(FunctionCode fc, string axName, bool right, object otherArg)
            {
                string kn = getKeyName(fc,axName,right);
                if (m_RM != null && m_RM.ContainsKey(kn))
                {
                    return m_RM[kn];
                }
                else
                {
                    string rs = string.Empty;
                    switch (fc.FCode)
                    {
                        case CommFunctionCode.Contact: rs = Respond.Contact(right); break;
                        case CommFunctionCode.ParameterSetting: rs = Respond.ParameterSetting(axName,right); break;
                        case CommFunctionCode.AccelerationSetting: rs = Respond.AccelerationSetting(axName
                            , otherArg == null 
                                ? Axle.AccelerationLevel.AccelerationLevelConstant
                                : (Axle.AccelerationLevel)otherArg
                            , right); break;
                        case CommFunctionCode.Run: rs = Respond.Run(axName,true); break;
                        case CommFunctionCode.Stop: rs = Respond.Stop(axName,right); break;
                        case CommFunctionCode.ToZero: rs = Respond.ToZero(axName,right); break;
                        case CommFunctionCode.Query: rs = Respond.QueryPostion(axName,right); break;
                        case CommFunctionCode.RelativeZero: rs = Respond.RelativeZero(axName,right); break;
                        case CommFunctionCode.ParameterPreserve: rs = Respond.ParameterPreserve(right); break;
                        case CommFunctionCode.WrongFormat: rs = Respond.WrongFormat(); break;
                        default: rs = string.Empty; break;
                    }
                    if (!string.IsNullOrEmpty(rs))
                    {
                        try
                        {
                            m_RM.Add(kn, rs);
                        }
                        catch (Exception ex)
                        {
                            Utility.FileOperate.WriteToLog(string.Format("ResponseManager.getResonseCode Ex:{0}",ex.Message));
                        }
                    }
                }
                return string.Empty;
            }
        }
        
        public class Respond
        {
            const string m_PT_REP_TURE = "T";
            const string m_PT_REP_FALSE = "F";

            internal static string getRepRst(bool right)
            {
                return
                    right ? m_PT_REP_TURE : m_PT_REP_FALSE;
            }

            /// <summary>
            /// 联络指令
            /// </summary>
            /// <returns></returns>
            public static string Contact(bool right)
            {
                StringBuilder contBd = new StringBuilder();
                contBd.Append(CommFlag.Response);
                contBd.Append(CommFlag.Contact);
                contBd.Append(FunctionCode.Contact);
                contBd.Append(CommFlag.Query);
                contBd.Append(getRepRst(right));
                string strSuffix = Protocol.getVerifyAndEndFlag(contBd.ToString());
                contBd.Append(strSuffix);
                //contBd.Append(CommFlag.AllEnd);
                return contBd.ToString();
            }


            /// <summary>
            /// 基本运行参数设置指令 
            /// </summary>
            /// <returns></returns>
            public static string ParameterSetting(string axleName,bool right)
            {
                StringBuilder contBd = new StringBuilder();
                contBd.Append(CommFlag.Response);
                contBd.Append(CommFlag.ParameterSetting);
                contBd.Append(FunctionCode.ParameterSetting);
                contBd.Append(axleName);
                contBd.Append(CommFlag.Space);
                contBd.Append(getRepRst(right));
                string strSuffix = Protocol.getVerifyAndEndFlag(contBd.ToString());
                contBd.Append(strSuffix);
                return contBd.ToString();
            }

            /// <summary>
            /// 加速度参数设置
            /// </summary>
            /// <param name="axleName"></param>
            /// <param name="aLevel"></param>
            /// <returns></returns>
            public static string AccelerationSetting(
                string axleName
                , Axle.AccelerationLevel aLevel
                ,bool right
             )
            {
                StringBuilder contBd = new StringBuilder();
                contBd.Append(CommFlag.Response);
                contBd.Append(CommFlag.AccelerationSetting);
                contBd.Append(FunctionCode.AccelerationSetting);
                contBd.Append(axleName);
                contBd.Append(CommFlag.Space);
                contBd.Append(aLevel.ToString());
                contBd.Append(getRepRst(right));
                string strSuffix = Protocol.getVerifyAndEndFlag(contBd.ToString());
                contBd.Append(strSuffix);
                return contBd.ToString();
            }


            /// <summary>
            /// 运行指令(单轴)
            /// </summary>
            /// <param name="axleNameList"></param>
            /// <returns></returns>
            public static string Run(string axleName,bool right)
            {
                StringBuilder contBd = new StringBuilder();
                contBd.Append(CommFlag.Run);
                contBd.Append(FunctionCode.Run);
                
                contBd.Append(axleName);

                contBd.Append(getRepRst(right));
                string strSuffix = Protocol.getVerifyAndEndFlag(contBd.ToString());
                contBd.Append(strSuffix);
                return contBd.ToString();
            }


            /// <summary>
            /// 停止指令(单轴)
            /// </summary>
            /// <param name="axleNameList"></param>
            /// <param name="isAll"></param>
            /// <returns></returns>
            public static string Stop(string axleName, bool right)
            {
                StringBuilder contBd = new StringBuilder();
                contBd.Append(CommFlag.Response);
                contBd.Append(CommFlag.Stop);
                contBd.Append(FunctionCode.Stop);
                
                contBd.Append(axleName);
                    
                contBd.Append(getRepRst(right));
                string strSuffix = Protocol.getVerifyAndEndFlag(contBd.ToString());
                contBd.Append(strSuffix);
                return contBd.ToString();
            }

            /// <summary>
            /// 归零指令 
            /// </summary>
            /// <param name="axleName"></param>
            /// <returns></returns>
            public static string ToZero(string axleName, bool right)
            {
                StringBuilder contBd = new StringBuilder();
                contBd.Append(CommFlag.Response);
                contBd.Append(CommFlag.ToZero);
                contBd.Append(FunctionCode.ToZero);
                contBd.Append(axleName);
                contBd.Append(CommFlag.Space);
                contBd.Append(getRepRst(right));
                string strSuffix = Protocol.getVerifyAndEndFlag(contBd.ToString());
                contBd.Append(strSuffix);
                return contBd.ToString();
            }

            /// <summary>
            /// 查询当前位置
            /// </summary>
            /// <param name="alxeName"></param>
            /// <returns></returns>
            public static string QueryPostion(string axleName, bool right)
            {
                StringBuilder contBd = new StringBuilder();
                contBd.Append(CommFlag.Response);
                contBd.Append(CommFlag.Query);
                contBd.Append(axleName);
                contBd.Append(CommFlag.Space);
                contBd.Append(getRepRst(right));
                string strSuffix = Protocol.getVerifyAndEndFlag(contBd.ToString());
                contBd.Append(strSuffix);
                return contBd.ToString();
            }

            /// <summary>
            /// 查询指令是否成功
            /// </summary>
            /// <param name="alxeName"></param>
            /// <returns></returns>
            public static string QuerySuccess(bool right)
            {
                StringBuilder contBd = new StringBuilder();
                contBd.Append(CommFlag.Response);
                contBd.Append(CommFlag.Query);
                contBd.Append(FunctionCode.QuerySuccess);
                contBd.Append(getRepRst(right));
                string strSuffix = Protocol.getVerifyAndEndFlag(contBd.ToString());
                contBd.Append(strSuffix);
                return contBd.ToString();
            }

            /// <summary>
            /// 相对零位设置
            /// </summary>
            /// <param name="axleName"></param>
            /// <returns></returns>
            public static string RelativeZero(string axleName, bool right)
            {
                StringBuilder contBd = new StringBuilder();
                contBd.Append(CommFlag.Response);
                contBd.Append(CommFlag.RelativeZero);
                contBd.Append(FunctionCode.RelativeZero);
                contBd.Append(axleName);
                contBd.Append(CommFlag.Space);
                contBd.Append(getRepRst(right));
                string strSuffix = Protocol.getVerifyAndEndFlag(contBd.ToString());
                contBd.Append(strSuffix);
                return contBd.ToString();
            }

            /// <summary>
            /// 相对零位设置
            /// </summary>
            /// <param name="axleName"></param>
            /// <returns></returns>
            public static string WrongFormat()
            {
                StringBuilder contBd = new StringBuilder();
                contBd.Append(CommFlag.Response);
                contBd.Append(FunctionCode.WrongFormat);
                string strSuffix = Protocol.getVerifyAndEndFlag(contBd.ToString());
                contBd.Append(strSuffix);
                return contBd.ToString();
            }

            /// <summary>
            /// 参数保留设置
            /// </summary>
            /// <param name="axleName"></param>
            /// <returns></returns>
            public static string ParameterPreserve(bool right)
            {
                StringBuilder contBd = new StringBuilder();
                contBd.Append(CommFlag.ParameterPreserve);
                contBd.Append(FunctionCode.ParameterPreserve);
                contBd.Append(Axle.AllAxleName);
                contBd.Append(CommFlag.Space);
                contBd.Append(getRepRst(right));
                return contBd.ToString();
            }

            /// <summary>
            /// 虚拟零位设置
            /// </summary>
            /// <param name="axleName"></param>
            /// <returns></returns>
            public static string VZero(string axleName,bool right)
            {
                StringBuilder contBd = new StringBuilder();
                contBd.Append(CommFlag.VZero);
                contBd.Append(FunctionCode.VZero);
                contBd.Append(axleName);
                contBd.Append(CommFlag.Space);
                contBd.Append(getRepRst(right));
                return contBd.ToString();
            }

        }

        public class RunFinished
        {
            const string m_PT_RF_SU = "EO";
            const string m_PT_RF_FD = "RE";

            internal static string getRunFinishedRst(bool right)
            {
                return
                    right ? m_PT_RF_SU : m_PT_RF_FD;
            }
        //End of Operation 操作结束，运算结束 EO
        //Runtime Error 中文解释 运行时错误 RE
        }


        public class UnpacketResult
        {
            public UnpacketResult()
            {
                m_result = false;
                m_commFlag = KZ400B.CommFlag.Empty;
                m_functionCode = KZ400B.FunctionCode.Empty;
                m_content = string.Empty;
                m_Action = AxleActions.AllActions;
                m_AxleName = string.Empty;
                m_Position = 0;
            }

            private bool m_result;

            public bool Result
            {
                get { return m_result; }
                set { m_result = value; }
            }

            private string m_commFlag;

            public string CommFlag
            {
                get { return m_commFlag; }
                set 
                {
                    
                        m_commFlag = value;

                        switch (m_commFlag)
                        {
                            case KZ400B.CommFlag.Contact: m_fcObject = KZ400B.FunctionCode.FCodeContact; break;
                            case KZ400B.CommFlag.ParameterSetting: m_fcObject = KZ400B.FunctionCode.FCodeParameterSetting; break;
                            case KZ400B.CommFlag.AccelerationSetting: m_fcObject = KZ400B.FunctionCode.FCodeAccelerationSetting; break;
                            case KZ400B.CommFlag.RelativeZero: m_fcObject = KZ400B.FunctionCode.FCodeRelativeZero; break;
                            case KZ400B.CommFlag.Query: m_fcObject = KZ400B.FunctionCode.FCodeQuery; break;
                            case KZ400B.CommFlag.ToZero: m_fcObject = KZ400B.FunctionCode.FCodeToZero; break;
                            case KZ400B.CommFlag.Run: m_fcObject = KZ400B.FunctionCode.FCodeRun; break;
                            case KZ400B.CommFlag.Stop: m_fcObject = KZ400B.FunctionCode.FCodeStop; break;
                            case KZ400B.CommFlag.StepperAngleFraction: m_fcObject = KZ400B.FunctionCode.FCodeStepperAngleFraction; break;
                            case KZ400B.CommFlag.ParameterPreserve: m_fcObject = KZ400B.FunctionCode.FCodeParameterPreserve; break;
                            case KZ400B.CommFlag.VZero: m_fcObject = KZ400B.FunctionCode.FCodeVZero; break;
                            default: m_fcObject = KZ400B.FunctionCode.FCodeWrongFormat; break;
                        }
                       
                }
            }

            public AxleActions getActionByCommFlag()
            {
                AxleActions act = AxleActions.AllActions;
                switch (m_commFlag)
                {
                    case KZ400B.CommFlag.Contact: act = AxleActions.ContactRespond; break;
                    case KZ400B.CommFlag.ParameterSetting: act = AxleActions.ParameterSettingRespond; break;
                    case KZ400B.CommFlag.AccelerationSetting: act = AxleActions.AccelerationSettingRespond; break;
                    case KZ400B.CommFlag.RelativeZero: act = AxleActions.RelativeZeroRespond; break;
                    case KZ400B.CommFlag.Query: act = AxleActions.QueryPositionRespond; break;
                    case KZ400B.CommFlag.ToZero: act = AxleActions.ToZeroRespond; break;
                    case KZ400B.CommFlag.Run : act = AxleActions.RunRespond; break;
                    case KZ400B.CommFlag.Stop: act = AxleActions.StopRespond; break;
                    case KZ400B.CommFlag.StepperAngleFraction: act = AxleActions.StepperAngleFractionRespond; break;
                    case KZ400B.CommFlag.ParameterPreserve: act = AxleActions.ParameterPreserveRespond; break;
                    case KZ400B.CommFlag.VZero: act = AxleActions.VZeroRespond; break;
                    default: act = AxleActions.Exception; break;
                }
                return act;
            }

            private string m_functionCode;

            public string FunctionCode
            {
                get { return m_functionCode; }
                set { 
                    
                    m_functionCode = value;
                    if (m_functionCode == KZ400B.FunctionCode.WrongFormat)
                        m_fcObject = KZ400B.FunctionCode.FCodeWrongFormat;

                }
            }

            private FunctionCode m_fcObject;

            public FunctionCode FunctionCodeObject
            {
                get { return m_fcObject; }
            }

            private AxleActions m_Action;

            public AxleActions Action
            {
                get { return m_Action; }
                internal set { m_Action = value; }
            }

            private string m_content;

            public string Content
            {
                get { return m_content; }
                set { m_content = value; }
            }

            private int m_Position;

            public int Position
            {
                get { return m_Position; }
                set { m_Position = value; }
            }

            private string m_AxleName;

            public string AxleName
            {
                get { return m_AxleName; }
                set { m_AxleName = value; }
            }


            public bool Approximate(UnpacketResult r)
            {
                //if (l == null && r == null) return true;
                //else if (l == null && r != null) return false;
                if (r == null) return false;

                return this.m_result == r.m_result
                    && this.m_commFlag == r.m_commFlag
                    && (string.IsNullOrEmpty(r.m_functionCode)
                           || this.m_functionCode == r.m_functionCode)
                    && this.m_Action == r.m_Action
                   && this.m_content.IndexOf(r.m_content) >= 0;
            }

            public bool UnApproximate(UnpacketResult r)
            {
                //if (l == null && r == null) return false;
                //else if (l == null && r != null) return true;
                // if (r == null) return true;

                //return this.m_result != r.m_result
                //    || this.m_commFlag != r.m_commFlag
                //    || this.m_functionCode != r.m_functionCode
                //    || this.m_content.IndexOf( r.m_content) < 0;

                return !Approximate(r);
            }
        }

        public static UnpacketResult Unpack(string data)
        {
            UnpacketResult rst = new UnpacketResult();
            if (!data.StartsWith(CommFlag.Response) || !data.EndsWith(CommFlag.AllEnd))
            {
                Console.WriteLine("Syntax ERROR");
                return rst;
            }
            string tmpString = data.TrimEnd(CommFlag.AllEnd[0]).TrimEnd(CommFlag.SingleEnd[0]);

            byte vCode1 = 0;
            byte vCode2 = 0;
            StringBuilder sComm = new StringBuilder();
            if (tmpString.Length > 2)
            {
                for (int i = 0; i < tmpString.Length - 2; i++)
                {
                    sComm.Append(tmpString[i]);
                }
                vCode1 = (byte)tmpString[tmpString.Length - 2];
                vCode2 = (byte)tmpString[tmpString.Length - 1];
            }
            string commString = sComm.ToString();
            if (!Verify.IsVerify(commString, vCode1, vCode2))
            {
                rst.Result = false;
                return rst;
                //throw new Exception("校验错误");
            }
            else
            {
                int tL = tmpString.Length - 2;
                tmpString = tmpString.Substring(0, tL);
            }

            if (tmpString.StartsWith(FunctionCode.Command))
            {
                rst.FunctionCode = FunctionCode.Command;
                return rst;
            }

            int offset = 0;
            bool upRst = false;
            if (tmpString.Length > offset + 1)
            {
                upRst = tmpString[offset++].ToString() == CommFlag.Response;
            }
            string cf = string.Empty;
            if (tmpString.Length > offset + 1)
            {
                cf = tmpString[offset++].ToString();
                rst.CommFlag = cf;
                rst.Action = rst.getActionByCommFlag();
            }

            if (string.IsNullOrEmpty(cf))
            {
                return rst;
            }


            string fc = string.Empty;
            if (cf != CommFlag.Query && tmpString.Length > offset + 1)
            {
                fc = tmpString[offset++].ToString();
                rst.FunctionCode = fc;
            }

            if (cf != CommFlag.Query && string.IsNullOrEmpty(fc))
            {
                return rst;
            }

            string axName = string.Empty;
            if ( tmpString.Length > offset + 1)
            {
                axName = tmpString[offset++].ToString();
                if(cf == CommFlag.Contact && axName == CommFlag.Query)
                {
                    axName = string.Empty;
                }
                rst.AxleName = axName;
                upRst = tmpString[offset++].ToString() == CommFlag.Space;

                //如果是查询位置命令,还需要判断后面是否有具体位置信息
                if (!upRst && cf == CommFlag.Query )
                {
                    --offset;
                    int aPos = 0;
                    if (int.TryParse(tmpString.Substring(offset), out aPos))
                    {
                        rst.Position = aPos;
                        rst.Action = AxleActions.QueryPositionFinish;
                        rst.Result = true;
                        return rst;
                    }
                }
            }

            if (!upRst ||
                    (cf != CommFlag.Contact && string.IsNullOrEmpty(axName))
                )
            {
                return rst;
            }

            Axle.AccelerationLevel aLevel = null;
            if (cf == CommFlag.AccelerationSetting && tmpString.Length > offset + 1)
            {
                string acc = tmpString[offset++].ToString();
                if (!string.IsNullOrEmpty(acc))
                {
                    aLevel = acc == Axle.AccelerationLevel.AccelerationLevelGatherWay.ToString()
                        ? Axle.AccelerationLevel.AccelerationLevelGatherWay
                        : Axle.AccelerationLevel.AccelerationLevelConstant
                        ;
                }
                if (aLevel == null)
                {
                    return rst;
                }
            }

            bool right = false;
            string lastString = tmpString.Substring(offset);
            if (!string.IsNullOrEmpty(lastString))
            {
                if (lastString.StartsWith(ProtocolV2.Respond.getRepRst(true)))
                {
                    right = true;
                    offset++;
                }
                else if (lastString.StartsWith(ProtocolV2.Respond.getRepRst(false)))
                {
                    right = false;
                    offset++;
                }
                else if (lastString.StartsWith(ProtocolV2.RunFinished.getRunFinishedRst(true)))
                {
                    right = true;
                    rst.Action = (AxleActions)((int)rst.Action + 20);
                        
                    offset += 2;
                }
                else if (lastString.StartsWith(ProtocolV2.RunFinished.getRunFinishedRst(false)))
                {

                    right = false;
                    rst.Action = (AxleActions)((int)rst.Action + 20);
                    offset += 2;
                }
                else if(cf == CommFlag.VZero)///如果是虚拟零点命令有可能回复 SM/RM/RE
                {
                    if (lastString.StartsWith("SM"))
                    {
                        right = true;
                        rst.Action = AxleActions.VZeroSetFinish;
                        offset += 2;
                    }
                    else if (lastString.StartsWith("RM"))
                    {
                        right = true;
                        rst.Action = AxleActions.VZeroRemoveFinish;
                        offset += 2;
                    }
                    else if (lastString.StartsWith("RE"))
                    {
                        right = false;
                        rst.Action = AxleActions.VZeroFailed;
                        offset += 2;
                    }
                }
                rst.Result = right;
            }

            return rst;
        }
    }
}
